/**
* compareFaces.cpp
*/

#include <iostream>
#include "../util/tinyxml2.h"
#include "cv.h"
#include "highgui.h"
#include "../util/LandmarkType.h"
#include "../util/Point.h"
#include "Face.h"
#include "Gallery.h"
#include <map>

using namespace tinyxml2;
using namespace std;

vector<Face> getFacesFromPhoto();
Gallery getFacesFromGallery();
string xmlFilePath;
double getLimit();

int main(int argc, char* argv[]) {
	if (argc >= 2) {
		xmlFilePath =  argv[1];
	}
	
	char algorithmType = 'p';
	if (argc >= 3) {
		algorithmType = argv[2][0];
	}

	vector<Face> faces = getFacesFromPhoto();
	Gallery gallery = getFacesFromGallery();
	
	gallery.calculateOffsetMatrix();
	gallery.calculateCovarianceMatrix();
	gallery.calculateEigenvectors();
	gallery.compareFace(faces[0], algorithmType, getLimit());

	return 0;
}

vector<Face> getFacesFromPhoto() {
	vector<Face> result;
	
	// Read all landmarks for face in photo
	XMLDocument landmarkInput;
	landmarkInput.LoadFile((xmlFilePath + "/landmarks.xml").c_str());
	
	Point* faceStartPos = NULL;
	Point* faceEndPos = NULL;

	// For all faces
	for (XMLElement* faceElement = landmarkInput.FirstChildElement("face"); 
		 faceElement != NULL;
	 	 faceElement = faceElement->NextSiblingElement("face")) {
			
		map<LandmarkType, Point> landmarks;
			 
	 	for (XMLElement* landmarkElement = faceElement->FirstChildElement("landmark"); 
	 		 landmarkElement != NULL;
	 	 	 landmarkElement = landmarkElement->NextSiblingElement("landmark")) {
			
			XMLElement* typeIdElement = landmarkElement->FirstChildElement("type_id");
		 	XMLText* typeIdText = typeIdElement->FirstChild()->ToText();
		 	LandmarkType typeId = (LandmarkType)atoi(typeIdText->Value());

			XMLElement* xElement = landmarkElement->FirstChildElement("x");
			XMLText* xText = xElement->FirstChild()->ToText();
			int xPos = atoi(xText->Value());
			
			XMLElement* yElement = landmarkElement->FirstChildElement("y");
			XMLText* yText = yElement->FirstChild()->ToText();
			int yPos = atoi(yText->Value());
			
			if (typeId == FACE_BOTTOM_LEFT || typeId == FACE_BOTTOM_RIGHT) {
				if (typeId == FACE_BOTTOM_LEFT) {
					faceStartPos = new Point(xPos, yPos);	
				}
				else {
					faceEndPos = new Point(xPos, yPos);
				}
			}
			else {
				landmarks[typeId] = Point(xPos, yPos);
			}
		}
		
		XMLElement* faceIdElement = faceElement->FirstChildElement("face_id");
		XMLText* faceIdText = faceIdElement->FirstChild()->ToText();
		int faceId = atoi(faceIdText->Value());
		
		// Add landmarks and calculate them in polar cooridnates
		Face face(faceId);
		face.addLandmarks(landmarks, *faceStartPos, *faceEndPos);
		face.calculatePairs();
		
		result.push_back(face);
	}
	
	return result;
}

Gallery getFacesFromGallery() {
	Gallery result;

	// Read all landmarks for face in photo
	XMLDocument landmarkInput;
	landmarkInput.LoadFile("../data/old_landmarks.xml");

	Point* faceStartPos = NULL;
	Point* faceEndPos = NULL;
	
	// For all faces
	for (XMLElement* faceElement = landmarkInput.FirstChildElement("face"); 
		 faceElement != NULL;
	 	 faceElement = faceElement->NextSiblingElement("face")) {
		
		map<LandmarkType, Point> landmarks;
			 
	 	for (XMLElement* landmarkElement = faceElement->FirstChildElement("landmark"); 
	 		 landmarkElement != NULL;
	 	 	 landmarkElement = landmarkElement->NextSiblingElement("landmark")) {
			
			XMLElement* typeIdElement = landmarkElement->FirstChildElement("type_id");
		 	XMLText* typeIdText = typeIdElement->FirstChild()->ToText();
		 	LandmarkType typeId = (LandmarkType)atoi(typeIdText->Value());
	
			XMLElement* xElement = landmarkElement->FirstChildElement("x");
			XMLText* xText = xElement->FirstChild()->ToText();
			int xPos = atoi(xText->Value());
			
			XMLElement* yElement = landmarkElement->FirstChildElement("y");
			XMLText* yText = yElement->FirstChild()->ToText();
			int yPos = atoi(yText->Value());
			
			if (typeId == FACE_BOTTOM_LEFT || typeId == FACE_BOTTOM_RIGHT) {
				if (typeId == FACE_BOTTOM_LEFT) {
					faceStartPos = new Point(xPos, yPos);	
				}
				else {
					faceEndPos = new Point(xPos, yPos);
				}
			}
			else {
				landmarks[typeId] = Point(xPos, yPos);
			}
		}
		
		XMLElement* faceIdElement = faceElement->FirstChildElement("face_id");
		XMLText* faceIdText = faceIdElement->FirstChild()->ToText();
		int faceId = atoi(faceIdText->Value());
		
		// Add landmarks and calculate them in polar cooridnates
		Face face(faceId);
		face.addLandmarks(landmarks, *faceStartPos, *faceEndPos);
		face.calculatePairs();

		result.addFace(face);
	}
	
	return result;
}

double getLimit() {
	XMLDocument configFile;
	configFile.LoadFile((xmlFilePath + "/config.xml").c_str());

	XMLElement* settingsElement = configFile.FirstChildElement("settings");
	XMLElement* limitElement = settingsElement->FirstChildElement("minimum_match_score");
	double limit = atof(limitElement->FirstChild()->ToText()->Value());
	
	return limit;
}
